package com.github.zhp;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.github.zhp.startup.ConfigJson;
import com.github.zhp.startup.TemplateEngineType;
import org.apache.ibatis.jdbc.ScriptRunner;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class ConfigurationDelegator implements Serializable {
    /**
     * 读取控制台输入内容
     */
    private final Scanner scanner = new Scanner(System.in);
    private ConfigJson config = new ConfigJson();
    private final DataSourceConfig DATA_SOURCE_CONFIG = new DataSourceConfig.Builder(config.getDatabaseUrl(), config.getUserName(), config.getPassword()).build();

    /**
     * 控制台输入内容读取并打印提示信息
     *
     * @param message 提示信息
     */
    public String scannerNext(String message) {
        System.out.println(message);
        String nextLine = scanner.nextLine();
        if (StringUtils.isBlank(nextLine)) {
            // 如果输入空行继续等待
            return scanner.next();
        }
        return nextLine;
    }

    public void setConfig(ConfigJson config) {
        this.config = config;
    }

    protected <T> T configBuilder(IConfigBuilder<T> configBuilder) {
        return null == configBuilder ? null : configBuilder.build();
    }

    /**
     * 执行开始
     */
    public void start() {
        System.out.println("！！！执行代码自动生成开始！！！");
    }

    /**
     * 数据源配置 Builder
     */
    public IConfigBuilder<DataSourceConfig> dataSourceConfigBuilder() {
//        return new DataSourceConfig
//                .Builder("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;CASE_INSENSITIVE_IDENTIFIERS=TRUE",
//                "sa", "");
        return new DataSourceConfig.Builder(config.getDatabaseUrl(), config.getUserName(), config.getPassword());
    }

    /**
     * 全局配置 Builder
     */
    public GlobalConfig.Builder globalConfigBuilder() {
        String outputDir = config.getOutPutDir();
        System.out.println("文件输出目录：" + outputDir);
        return new GlobalConfig.Builder().fileOverride().enableSwagger().outputDir(outputDir).author(config.getAuthor()).dateType(DateType.ONLY_DATE);
    }

    /**
     * 生成文件包名配置 Builder
     */
    public PackageConfig.Builder packageConfigBuilder() {
        return new PackageConfig.Builder().parent(config.getPackageName()).moduleName(config.getModuleName());
    }

    /**
     * 自定义模板配置 Builder
     */
    public TemplateConfig.Builder templateConfigBuilder() {
        return new TemplateConfig.Builder();
    }

    /**
     * 代码生成策略配置 Builder
     */
    public IConfigBuilder<StrategyConfig> strategyConfigBuilder() {
//        scannerNext("\n请输入表名多个英文逗号分隔："

        return new StrategyConfig.Builder().addInclude(config.getIncludes().split(",")).entityBuilder().naming(NamingStrategy.underline_to_camel).controllerBuilder().enableRestStyle().mapperBuilder().enableBaseColumnList().enableBaseResultMap();
    }

    /**
     * 注入配置 Builder
     */
    public IConfigBuilder<InjectionConfig> injectionConfigBuilder() {
        return new InjectionConfig.Builder();
    }

    /**
     * 代码生成，模板引擎
     */
    public AbstractTemplateEngine templateEngine() {
        TemplateEngineType templateEngineType = config.getTemplateEngineType();
        if (templateEngineType == TemplateEngineType.velocity) {
            return new VelocityTemplateEngine();
        } else if (templateEngineType == TemplateEngineType.freemarker) {
            return new FreemarkerTemplateEngine();
        }
        return new FreemarkerTemplateEngine();
    }

    public DataSourceConfig getDataSourceConfig() {
        return configBuilder(this.dataSourceConfigBuilder());
    }

    public GlobalConfig getGlobalConfig() {
        return configBuilder(this.globalConfigBuilder());
    }

    public TemplateConfig getTemplateConfig() {
        TemplateConfig.Builder controller = this.templateConfigBuilder().controller(config.getControllerTemplatePath()).entity(config.getEntityTemplatePath()).mapper(config.getMapperTemplatePath()).mapperXml(config.getMapperXmlTemplatePath()).service(config.getServiceTemplatePath(), config.getServiceImplTemplatePath());
        return configBuilder(controller);
    }

    public PackageConfig getPackageConfig() {
        Map<OutputFile, String> map = new HashMap<>();
        String outputDir = getGlobalConfig().getOutputDir();
        int javaIndex = outputDir.lastIndexOf("java");
        String root = outputDir.substring(0, javaIndex);
        if (!StringUtils.endsWith(outputDir, File.separator)) {
            outputDir += File.separator;
        }
        String replace = root + File.separator + "resources" + File.separator + "mapper";
        map.put(OutputFile.mapperXml, replace);
        //自定义生成路径
        final String rootPath = outputDir;

        Map<String, String> packageInfo = new HashMap<>();
        if (CollectionUtils.isNotEmpty(config.getPathInfoMap())) {
            config.getPathInfoMap().forEach((k, v) -> {
                if (StringUtils.isNotBlank(v)) {
                    if (k != OutputFile.mapperXml) {
                        String packageKey = StringUtils.concatCapitalize(StringPool.EMPTY, k.name());
                        packageInfo.put(packageKey, v);
                    }
                    v = v.replaceAll("\\.", StringPool.BACK_SLASH + File.separator);
                    v = rootPath + v;
                    map.put(k, v);
                }
            });
        }
        PackageConfig.Builder builder = this.packageConfigBuilder().pathInfo(map);
        builder.packageInfo(packageInfo);
        return configBuilder(builder);
    }

    public StrategyConfig getStrategyConfig() {
        return configBuilder(this.strategyConfigBuilder());
    }

    public InjectionConfig getInjectionConfig() {
        return configBuilder(this.injectionConfigBuilder());
    }

    public void init() throws SQLException, IOException {
        Connection conn = DATA_SOURCE_CONFIG.getConn();
        InputStream inputStream = Files.newInputStream(Paths.get(config.getSqlFilePath()), StandardOpenOption.READ);
        ScriptRunner scriptRunner = new ScriptRunner(conn);
        scriptRunner.setAutoCommit(true);
        scriptRunner.runScript(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        conn.close();
    }
}
